import worker, { ErrorEvent, MessageEvents, ThreadWorkerGlobalScope } from '@ohos.worker'; // 导入 worker包 // 导入 worker包
import Logger from '../common/utils/Logger';

/**
 * Worker注意事项：
 * 1.Worker存在数量限制，当前支持最多同时存在8个Worker。
 * 2.在API version 8及之前的版本，当Worker数量超出限制时，会抛出错误Error "Too many workers, the number of workers exceeds the maximum."。
 * 3.从API version 9开始，当Worker数量超出限制时，会抛出错误BusinessError "Worker initialization failure, the number of workers exceeds the maximum."。
 * 4.主动销毁Worker可以调用新创建Worker对象的terminate()或workerPort.close()方法。
 * 5.自API version 9版本开始，若Worker处于已经销毁或正在销毁等非运行状态时，调用其功能接口，会抛出相应的BusinessError。
 * 6.Worker的创建和销毁耗费性能，建议管理已创建的Worker并重复使用。
 * 7.创建Worker工程时，new worker.Worker构造函数和new worker.ThreadWorker构造函数不能同时使用，否则将导致工程中Worker的功能异常。自API version 9版本开始，建议使用new worker.ThreadWorker构造函数，在API version 8及之前的版本，建议使用new worker.Worker构造函数。
 * 8.创建Worker工程时，在Worker线程的文件中（比如本文中worker.ts）不能导入任何有关构建UI的方法（比如ETS文件等），否则会导致Worker的功能失效。排查方式：解压生成的Hap包，在创建Worker线程的文件目录中找到"worker.js"，全局搜索"View"关键字。如果存在该关键字，说明在worker.js中打包进去了构建UI的方法，会导致Worker的功能失效，建议在创建Worker线程的文件中修改 "import “xxx” from src"中src的目录层级。
 * 9.线程间通信时传递的数据量最大限制为16M。
 * 10.Ability类型的Module支持使用Worker，Library类型的Module不支持使用Worker。
 * 11.创建Worker不支持使用其他Module的Worker.ts文件，即不支持跨模块调用Worker。
 * 12.由于不同线程中上下文对象是不同的，因此Worker线程只能使用线程安全的库，例如UI相关的非线程安全库不能使用。
 */
const TAG_WORKER = 'my_worker';

// worker.workerPort 属性是 worker 线程用于与宿主线程通信的对象
let workerPort: ThreadWorkerGlobalScope = worker.workerPort;

/**
 * 处理来自主线程的消息，在这里运行worker线程的业务逻辑计算
 * 即，在主线程实例化的worker对象调用 postMessage 方法时传递的参数
 * ```ts
 * // 主线程代码：创建一个worker线程,运行 my_worker.ts 代码
 * let workInstance = new worker.ThreadWorker("entry/ets/workers/my_worker.ts");
 * // 向worker线程推送消息
 * workInstance.postMessage(message);
 *
 * ```
 * workerPort.onmessage(event: MessageEvents) => void
 * Worker对象的onmessage属性表示宿主线程接收到来自其创建的Worker通过workerPort.postMessage接口发送的消息时被调用的事件处理程序，处理程序在宿主线程中执行。
 *
 * event.data 即：收到主线程发来的消息数据，该数据对象必须是可序列化。
 * 支持的数据类型有：
 *  - 所有基础类型（不包括symbol）：undefined、Null、Boolean、Number、String、BigInt
 *  - Date
 *  - String
 *  - RegExp
 *  - Array
 *  - Map
 *  - Set
 *  - Object（只支持Plain Object，不支持带function的）
 *  - ArrayBuffer（提供transfer能力）
 *  - TypedArray
 */
workerPort.onmessage = function (event: MessageEvents) {
  // data：主线程发送的信息
  let data = event.data;
  Logger.info(TAG_WORKER, "onmessage -> message from parent : " + JSON.stringify(data))
  // 要向主线程传递的消息
  let message = {
    thread: TAG_WORKER,
    message: 'message from worker thread.'
  }
  // 发送消息到主线程，该数据对象必须是可序列化
  workerPort.postMessage(message);

  // 销毁worker线程，根据实际需求决定是在worker内部控制销毁，还是交给主线程控制调用workerInstance.close()进行销毁
  // workerPort.close();
}

/**
 * worker线程onmessage()方法执行发生error的回调
 * ThreadWorkerGlobalScope的onmessageerror属性表示当Worker对象接收到一条无法被反序列化的消息时被调用的事件处理程序，处理程序在Worker线程中执行。
 * 即：上面的 onmessage(event) 方法参数 event.data 对象无法被反序列化时触发 onmessageerror(event) 方法
 */
workerPort.onmessageerror = function (event: MessageEvents) {
  Logger.info(TAG_WORKER, "onmessageerror -> 宿主线程发送的消息无法被反序列化！")
}

/**
 * worker线程发生error的回调
 * GlobalScope的onerror属性表示Worker在执行过程中发生异常被调用的事件处理程序，处理程序在Worker线程中执行。
 */
workerPort.onerror = function (event: ErrorEvent) {
  Logger.info(TAG_WORKER, "onerror -> " + JSON.stringify(event))
}